//
//  KQNewWebViewController.swift
//  FastContact
//
//  Created by 张文生 on 2019/5/27.
//  Copyright © 2019 shaniaoge. All rights reserved.
//

import UIKit
import WebKit
import JavaScriptCore
import HandyJSON

private  let kWKWebViewProgressKeyPath = "estimatedProgress"
private  let kWKWebViewTitle = "title"

@objc protocol KQNewWebViewControllerDelegate:class{
    @objc optional
    func webViewController(_ vc:KQNewWebViewController,didStartLoading URL:URL?) -> Void
    @objc optional
    func webViewController(_ vc:KQNewWebViewController,didFinishLoading URL:URL?) -> Void
    @objc optional
    func webViewController(_ vc:KQNewWebViewController,didFailToLoaded URL:URL?,with error:Error) -> Void
    @objc optional
    //0 不允许 1 允许
    func webViewController(_ vc:KQNewWebViewController,decidePolictForScheme scheme:String,request URL:URL?,actionType:WKNavigationType) -> Bool
    
    //0 不允许 1 允许
    @objc optional
    func webViewController(_ vc:KQNewWebViewController,decidePolictForAction URL:URL?,actionType:WKNavigationType) -> Bool
    
    @objc optional
    func webViewController(_ vc:KQNewWebViewController,didReceiveMessage name:String,content object:Any?) -> Void
}

typealias KQNewEvaluateJSCompletion = (Any?,Error?) -> Void

private class LeakAvoider :NSObject,WKScriptMessageHandler{
    weak var delegate:WKScriptMessageHandler?
    
    func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
        self.delegate?.userContentController(userContentController, didReceive: message)
    }

    init(delegate:WKScriptMessageHandler) {
        self.delegate = delegate
        super.init()
    }
}

class KQNewWebViewController:UIViewController{
    
//    weak var delegate:KQNewWebViewControllerDelegate? 暂时废除代理 用闭包
    
    var wkwebViewsAllFrame:NSMutableArray = NSMutableArray()
    var jsMessageNames:NSMutableArray = NSMutableArray()
    
    //二选一
    var startHandle:((URL?)->Void)? //开始 回调url
    var finishHandle:(()->Void)?  //完后
    var failHandle:(()->Void)? //失败
    
    var decidePolictForScheme:((_ scheme:String,_ URL:URL?,_ actionType:WKNavigationType)->Bool)?  //0 不允许 1 允许
    var decidePolictForAction:((_ URL:URL?,_ actionType:WKNavigationType)->Bool)?
    
    var messageRecevied:((String,Any?)->Void)? //注册JS回调
    
    var scrollView:UIScrollView!{
        get {
            return wkWebView.scrollView
        }
    }
    
    private(set) var wkWebView:WKWebView!
    
    var url:String?{
        get{
            return wkWebView.url?.absoluteString
        }
    }
    
    //默认绿色
    var tintColor:UIColor = UIColor.green{
        didSet{
            progressView?.tintColor = tintColor
        }
    }
    
//    //暂时这样 没啥用处 每个都显示进度条
//    var progressViewHidden:Bool = false{
//        didSet{
//            progressView?.isHidden = progressViewHidden
//        }
//    }
    
    var _progressView:UIProgressView?
    var progressView:UIProgressView?{
        get{
            if _progressView != nil {
                return _progressView
            }
            let p = UIProgressView.init(progressViewStyle: UIProgressView.Style.default)
            p.autoresizingMask = UIView.AutoresizingMask(rawValue: UIView.AutoresizingMask.flexibleWidth.rawValue | UIView.AutoresizingMask.flexibleTopMargin.rawValue)
            _progressView = p
            return p
        }
    }
    
    //默认导航栏
    var progressDisplayedInView:UIView?{
        didSet{
            if progressDisplayedInView != nil {
                progressView?.removeFromSuperview()
                progressView?.trackTintColor = UIColor.white
                progressView?.tintColor = tintColor
                progressDisplayedInView?.addSubview(self.progressView!)
                progressView?.frame = CGRect.init(x: 0, y: progressDisplayedInView!.frame.height - 2, width: progressDisplayedInView!.frame.width, height: 2)
            }
        }
    }
    
    override func viewDidLoad() {
        super.viewDidLoad()
        setupWebView()
    }
    
    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        if let display = progressDisplayedInView{
            self.progressDisplayedInView = display
        }else{
            self.progressDisplayedInView = self.navigationController?.navigationBar
        }
    }
    
    init() {
        super.init(nibName: nil, bundle: nil)
        addJSPath(nil)
    }
    
    init(_ JSPath:String?) {
        super.init(nibName: nil, bundle: nil)
        self.addJSPath(JSPath)
    }
    
    override func viewWillDisappear(_ animated: Bool) {
        super.viewWillAppear(animated)
        self.progressView?.removeFromSuperview()
    }
    
    deinit {
        wkWebView.navigationDelegate = nil
        wkWebView.uiDelegate = nil
        wkWebView.removeObserver(self, forKeyPath: kWKWebViewProgressKeyPath)
        wkWebView.removeObserver(self, forKeyPath: kWKWebViewTitle)
        removeAllJSMessages()
        removeDelegates()
        print("deinit --- KQNewWebViewController ---")
    }
    
    override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?) {
        super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)
    }
    
    //本地JS路径
    func addJSPath(_ JSPath:String?) -> Void {
        if let jsp = JSPath ,let path = try? String.init(contentsOfFile: jsp, encoding: String.Encoding.utf8) {
            let script = WKUserScript.init(source: path, injectionTime: WKUserScriptInjectionTime.atDocumentStart, forMainFrameOnly: false)
            let config = WKWebViewConfiguration()
            config.userContentController.addUserScript(script)
            wkWebView = createWKWebViewWithConfigure(config)
        }else{
            wkWebView = createWKWebViewWithConfigure(nil)
        }
    }
    
    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    func createWKWebViewWithConfigure(_ config:WKWebViewConfiguration?) -> WKWebView {
        if let config = config {
            return WKWebView.init(frame: CGRect.zero, configuration: config)
        }else{
            return WKWebView.init(frame: CGRect.zero)
//            return WKWebView.init(frame: CGRect.zero,configuration:WKWebViewConfiguration())
        }
    }
    
    func setupWebView() -> Void {
        setupWKWebView(wkWebView)
        validWKWebView(wkWebView)
    }
    
    func setupWKWebView(_ wk:WKWebView) -> Void {
        wk.frame = view.bounds
        wk.autoresizingMask = UIView.AutoresizingMask(rawValue: UIView.AutoresizingMask.flexibleWidth.rawValue |  UIView.AutoresizingMask.flexibleHeight.rawValue)
        wk.navigationDelegate = self
        wk.uiDelegate = self
        wk.isMultipleTouchEnabled = true
        wk.autoresizesSubviews = true
        wk.allowsBackForwardNavigationGestures=true
        wk.scrollView.alwaysBounceVertical = true
        if #available(iOS 11.0, *) {
            wk.scrollView.contentInsetAdjustmentBehavior = .never
        } else {
            // Fallback on earlier versions
            self.automaticallyAdjustsScrollViewInsets = false
        }
        view.addSubview(wk)
    }
    
    func invalidWKWebView(_ wk:WKWebView) -> Void {
        wk.isHidden = true
        wk.uiDelegate = nil
        wk.navigationDelegate = nil
        wk.scrollView.delegate = nil
        wk.removeObserver(self, forKeyPath: kWKWebViewProgressKeyPath)
        wk.removeObserver(self, forKeyPath: kWKWebViewTitle)
    }
    
    func validWKWebView(_ wk:WKWebView) -> Void {
        wk.isHidden = false
        wk.addObserver(self, forKeyPath: kWKWebViewProgressKeyPath, options: [], context: nil)
        wk.addObserver(self, forKeyPath: kWKWebViewTitle, options: [], context: nil)
        wk.superview?.bringSubviewToFront(wk)
    }
}

//MARK:类方法直接条用
extension KQNewWebViewController{
    //加载本地JS
    static func WebJSPath(_ JSPath:String) -> KQNewWebViewController{
        let webCtrl = KQNewWebViewController()
        return webCtrl
    }
    
    //加载URL链接
    static func WebURL(_ url:String?) -> KQNewWebViewController{
        let webCtrl = KQNewWebViewController()
        webCtrl.loadURLString(url ?? "")
        return webCtrl
    }
    
    //加载html
    static func WebHTML(_ HTML:String)-> KQNewWebViewController{
        let webCtrl = KQNewWebViewController()
        webCtrl.loadHTML(HTML)
        return webCtrl
    }
    
}

//MARK:方法
extension KQNewWebViewController{
    func stopLoading() -> Void { wkWebView.stopLoading() }
    func reload() -> Void { wkWebView.reload()}
    func canGoForward() -> Bool { return wkWebView.canGoForward }
    func goForward() -> Void { wkWebView.goForward()}
    
    func canGoBack() -> Bool {
        var can = wkWebView.canGoBack
        if !can {
            can = wkwebViewsAllFrame.count != 0
        }
        return can
    }
    
    func goBack() -> Void {
        if wkWebView.canGoBack {
            wkWebView.goBack()
        }else if(wkwebViewsAllFrame.count != 0){
            let lastWk = wkwebViewsAllFrame.lastObject as! WKWebView
            let curWk = wkWebView
            validWKWebView(lastWk)
            invalidWKWebView(curWk!)
            curWk!.removeFromSuperview()
            wkWebView = lastWk
            wkwebViewsAllFrame.remove(lastWk)
            self.startHandle?(wkWebView?.url)
        }
    }
    
    //根据链接加载
    func loadURL(_ url:URL) -> Void {
        let request = URLRequest.init(url: url, cachePolicy: URLRequest.CachePolicy.reloadRevalidatingCacheData, timeoutInterval: 30.0)
        wkWebView.load(request)
    }
    
    func loadURLString(_ url:String) -> Void {
        if let requestUrl = URL.init(string: url) {
            loadURL(requestUrl)
        }
    }
    
    func loadHTML(_ HTML:String) -> Void {
        loadHTML(HTML, nil)
    }
    
    func loadHTML(_ HTML:String,_ baseURL:URL?) -> Void {
        wkWebView.loadHTMLString(HTML, baseURL: baseURL)
    }
    
    func removeDelegates() -> Void {
        self.scrollView.delegate = nil
        self.wkwebViewsAllFrame.enumerateObjects { (wk, _, _) in
            (wk as! WKWebView).uiDelegate = nil
            (wk as! WKWebView).navigationDelegate = nil
            (wk as! WKWebView).scrollView.delegate = nil
        }
    }
    
    //运行js代码 OC调用JS
    func runJSCode(_ js:String,_ complete:KQNewEvaluateJSCompletion?) -> Void {
        wkWebView.evaluateJavaScript(js, completionHandler: complete)
    }
    
    //注册一个js消息名。代理将会收到js中的该函数调用。成对调用 否则会出现内存泄露 JS调用OC
    func addJSMessageName(_ js:String?) -> Void {
        guard let JS = js else { return ; }
        if jsMessageNames.contains(JS) { return;}
        jsMessageNames.add(JS)
        let user = wkWebView.configuration.userContentController
        //循环引用的解决
        user.add(LeakAvoider.init(delegate: self), name: JS)
    }
    
    func removeAllJSMessages() -> Void {
        for JS in jsMessageNames {
            let user = wkWebView.configuration.userContentController
            user.removeScriptMessageHandler(forName: JS as! String)
        }
        jsMessageNames.removeAllObjects()
        wkwebViewsAllFrame.removeAllObjects()
    }
}

extension KQNewWebViewController:WKNavigationDelegate{
    func webView(_ webView: WKWebView, didStartProvisionalNavigation navigation: WKNavigation!) {
        if webView == self.wkWebView {
            self.progressView?.isHidden = false
            self.progressView?.setProgress(0.1, animated: true)
        }
    }
    
    func webView(_ webView: WKWebView, didCommit navigation: WKNavigation!) {
        if webView == wkWebView { self.startHandle?(webView.url) }
    }
    
    func webView(_ webView: WKWebView, didFailProvisionalNavigation navigation: WKNavigation!, withError error: Error) {
        title = "Not Found"
        if webView == self.wkWebView { self.failHandle?() }
    }
    
    func webView(_ webView: WKWebView, didFail navigation: WKNavigation!, withError error: Error) {
        title = "Not Found"
        if webView == self.wkWebView { self.failHandle?() }
    }
    
    func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
        if webView == self.wkWebView { self.finishHandle?()}
    }
    
    func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) {
        guard let URL = navigationAction.request.url else {
            decisionHandler(WKNavigationActionPolicy.cancel)
            return ;
        }
        if URL.isFileURL {
            decisionHandler(WKNavigationActionPolicy.allow)
            return ;
        }
        
        //host
        if URL.absoluteString == "about:blank" {
            decisionHandler(WKNavigationActionPolicy.allow)
            return;
        }
        
        /**
         safari 不支持swf视频文件，需要屏蔽。参考请求这个链接：http://36kr.com/p/5041098.html
         */
        let extenstion = URL.pathExtension
        if extenstion == "swf" {
            decisionHandler(WKNavigationActionPolicy.cancel)
            return ;
        }
        
        //scheme
        guard let scheme = URL.scheme else {
            decisionHandler(WKNavigationActionPolicy.cancel)
            return ;
        }
        
        let isCanOpenAppStore = URL.absoluteString.contains("https://itunes.apple.com/cn/app/")
        if (scheme == "tel" ||
            scheme == "telprompt" ||
            scheme == "sms" ||
            scheme == "email" ||
            isCanOpenAppStore ) && UIApplication.shared.canOpenURL(URL)
        {
            UIApplication.shared.openURL(URL)
            decisionHandler(WKNavigationActionPolicy.allow)
            return;
        }
        
//        if scheme == "快洽自定义scheme" {
//        //[[YGRouter router] handleURL:URL];  路由占位
//        decisionHandler(WKNavigationActionPolicyCancel);
//        return;
        
        if let decidePolictForScheme = self.decidePolictForScheme {
            let polcy = decidePolictForScheme(scheme,URL,navigationAction.navigationType)
            if polcy == false { decisionHandler(.cancel) ;return ; }
        }
        
        if let decidePolictForAction = self.decidePolictForAction {
            let polcy = decidePolictForAction(URL,navigationAction.navigationType)
            return decisionHandler(polcy == false ? .cancel : .allow)
        }
        
        return decisionHandler(WKNavigationActionPolicy.allow)
        
    }
    
    func webView(_ webView: WKWebView, decidePolicyFor navigationResponse: WKNavigationResponse, decisionHandler: @escaping (WKNavigationResponsePolicy) -> Void) {
        decisionHandler(WKNavigationResponsePolicy.allow)
    }
    
    func webView(_ webView: WKWebView, didReceiveServerRedirectForProvisionalNavigation navigation: WKNavigation!) {
        
    }
    
    func webView(_ webView: WKWebView, didReceive challenge: URLAuthenticationChallenge, completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) {
        if challenge.protectionSpace.authenticationMethod == NSURLAuthenticationMethodServerTrust {
            let card = URLCredential.init(trust: challenge.protectionSpace.serverTrust!)
            completionHandler(URLSession.AuthChallengeDisposition.useCredential,card)
        }
    }
    
}

extension KQNewWebViewController:WKUIDelegate{
    func webView(_ webView: WKWebView, createWebViewWith configuration: WKWebViewConfiguration, for navigationAction: WKNavigationAction, windowFeatures: WKWindowFeatures) -> WKWebView? {
        if (navigationAction.request.url?.absoluteString.count ?? 0) != 0 {
            webView.load(navigationAction.request)
            return nil
        }
        
        let targetWK = createWKWebViewWithConfigure(configuration)
        setupWKWebView(targetWK)
        validWKWebView(targetWK)
        invalidWKWebView(self.wkWebView)
        wkwebViewsAllFrame.add(self.wkWebView)
        wkWebView = targetWK
        return targetWK
    }
    
    func webView(_ webView: WKWebView, runJavaScriptAlertPanelWithMessage message: String, initiatedByFrame frame: WKFrameInfo, completionHandler: @escaping () -> Void) {
        let  alret = UIAlertController.init(title: message, message: nil, preferredStyle: UIAlertController.Style.alert)
        alret.addAction(UIAlertAction.init(title: "确定", style: UIAlertAction.Style.default, handler: { (_) in
            completionHandler()
        }))
        present(alret, animated: true, completion: nil)
    }
    
    func webView(_ webView: WKWebView, runJavaScriptConfirmPanelWithMessage message: String, initiatedByFrame frame: WKFrameInfo, completionHandler: @escaping (Bool) -> Void) {
        let  alret = UIAlertController.init(title: message, message: nil, preferredStyle: UIAlertController.Style.alert)
        alret.addAction(UIAlertAction.init(title: "取消", style: UIAlertAction.Style.cancel, handler: { (_) in
            completionHandler(false)
        }))
        alret.addAction(UIAlertAction.init(title: "确定", style: UIAlertAction.Style.default, handler: { (_) in
            completionHandler(true)
        }))
        present(alret, animated: true, completion: nil)
    }
    
    func webView(_ webView: WKWebView, runJavaScriptTextInputPanelWithPrompt prompt: String, defaultText: String?, initiatedByFrame frame: WKFrameInfo, completionHandler: @escaping (String?) -> Void) {
        let  alret = UIAlertController.init(title: prompt, message: nil, preferredStyle: UIAlertController.Style.alert)
        alret.addTextField { (textFiled) in
            textFiled.text = defaultText
        }
        alret.addAction(UIAlertAction.init(title: "完成", style: UIAlertAction.Style.default, handler: {[weak alret] (action) in
            completionHandler(alret?.textFields?[0].text ?? "")
        }))
        present(alret, animated: true, completion: nil)
    }
}

extension KQNewWebViewController:WKScriptMessageHandler{
    func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
        //1 虚拟  2实物
        self.messageRecevied?(message.name,message.body)
    }
}

//KVO
extension KQNewWebViewController{
    override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
        guard let keyPath = keyPath , let wk = object as? WKWebView,wk == wkWebView else { return ; }
        
        if keyPath == kWKWebViewProgressKeyPath {
            
            let progress :Float =  Float(wkWebView.estimatedProgress)
//            self.progressView?.isHidden = progressViewHidden
            self.progressView?.isHidden = false
            let animated = progress > (progressView?.progress ?? 0 )
            self.progressView?.setProgress(progress, animated: animated)
            if progress >= 1.0{
                UIView.animate(withDuration: 0.3, delay: 0.3, options: UIView.AnimationOptions.curveEaseInOut, animations: {
                    self.progressView?.isHidden = true
                }) { (finishe) in
                    self.progressView?.progress = 0
                }
            }
        }else if (keyPath == kWKWebViewTitle){
            self.title = wkWebView.title
        }
    }
    
    override func viewDidDisappear(_ animated: Bool) {
        super.viewDidDisappear(animated)
    }
}
